package com.douban.business;

import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;

import com.core.AbstractConstant;
import com.core.UserRequest;
import com.douban.constants.DoubanMediaTypeConstant;
import com.douban.constants.DoubanUserActionConstant;

public class DoubanUserRequest extends UserRequest {

	private String username;
	private DoubanMediaTypeConstant[] mediaTypes;
	private DoubanUserActionConstant[] actions;
	private LinkedList requestCombination;
	private int start = 0;

	public DoubanUserRequest(String username) {
		init(username, null, null);
	}

	public DoubanUserRequest(String username, DoubanMediaTypeConstant[] mediaTypes,
			DoubanUserActionConstant[] actions) {
		init(username, mediaTypes, actions);
	}

	public DoubanMediaTypeConstant[] getMediaTypes() {
		return mediaTypes;
	}

	public DoubanUserActionConstant[] getUserActions() {
		return actions;
	}

	public String getUsername() {
		return username;
	}

	public int getStart() {
		return start;
	}

	/**
	 * calculate the start for next load
	 * 
	 * @param start
	 */
	public int calcStart(int start) {
		this.start = this.start + start;
		return this.start;
	}

	private void init(String username2, DoubanMediaTypeConstant[] mediaTypes2,
			DoubanUserActionConstant[] actions2) {
		this.username = username2;
		this.actions = actions2;
		this.mediaTypes = mediaTypes2;
		this.start = 0;
		this.requestCombination = new LinkedList();
		if (actions == null || actions2.length == 0) {
			this.actions = (DoubanUserActionConstant[]) DoubanUserActionConstant
					.getAllConstants(DoubanUserActionConstant.class).toArray(new DoubanUserActionConstant[DoubanUserActionConstant
					                                                              					.getAllConstants(DoubanUserActionConstant.class).size()]);
		}
		if (mediaTypes == null || mediaTypes.length == 0) {
			this.mediaTypes = (DoubanMediaTypeConstant[]) DoubanMediaTypeConstant
					.getAllConstants(DoubanMediaTypeConstant.class).toArray(new DoubanMediaTypeConstant[DoubanMediaTypeConstant
					                                                                					.getAllConstants(DoubanMediaTypeConstant.class).size()]);
		}
		
		//breakdown requests into request combination list
		DoubanMediaTypeConstant[] ts = this.mediaTypes;
		DoubanUserActionConstant[] as = this.actions;

		for (int i = 0; i < ts.length; i++) {
			DoubanMediaTypeConstant mediaType = ts[i];
			for (int j = 0; j < as.length; j++) {
				DoubanUserActionConstant userAction = as[j];
				this.requestCombination.add(new AbstractConstant[]{ts[i],as[j]} );
			}
		}
	}

	public String toString() {
		return username + mediaTypes + actions;
	}

	/**
	 * substract action only happens when the substruct base has more elements than the substructing item
	 * substract the cases from request combination list
	 */
	public synchronized void substractRequest(UserRequest ur) {
		if((ur instanceof DoubanUserRequest)&& username.equals(ur.getUsername())){
			DoubanUserRequest dur = (DoubanUserRequest)ur;
			Collection otherRequestCombinations = dur.getRequests();
			 
			Iterator itr = otherRequestCombinations.iterator();
			while (itr.hasNext()) {
				AbstractConstant[] cs = (AbstractConstant[]) itr.next();
				Iterator thisItr = this.requestCombination.iterator();
				while (thisItr.hasNext()) {
					AbstractConstant[] thiscs = (AbstractConstant[]) thisItr.next();
					if(Arrays.equals(cs, thiscs)){
						thisItr.remove();
					}
				}
			}
			
			refreshTypesAndActionArray();
		}
	}
	
	private void refreshTypesAndActionArray(){
		//check if the requestion combination list still has any action to any media type
		LinkedList retTList = new LinkedList();
		LinkedList retAList = new LinkedList();
		for (int i = 0; i < mediaTypes.length; i++) {
			DoubanMediaTypeConstant type = mediaTypes[i];
			int counter = 0;
			DoubanUserActionConstant action = null; 
			for (int j = 0; j < actions.length; j++) {
				int removeActionCounter = mediaTypes.length;
				action = actions[j];
				
				Iterator itr = this.requestCombination.iterator();
				while (itr.hasNext()) {
					AbstractConstant[] req = (AbstractConstant[]) itr.next();
					DoubanMediaTypeConstant mediaType = null;
					DoubanUserActionConstant userAction = null;
					for (int k = 0; k < req.length; k++) {
						AbstractConstant ar = req[k];
						if(req[k] instanceof DoubanMediaTypeConstant){
							mediaType = (DoubanMediaTypeConstant)req[k];
						}
						if(req[k] instanceof DoubanUserActionConstant){
							userAction = (DoubanUserActionConstant)req[k];
						}							
					}
					if((mediaType!=null||userAction!=null)&&
							mediaType.equals(type)&& userAction.equals(action)){
						//now we get an action to the type, we keep it later
						counter ++;
						removeActionCounter --;
					}
				}
				// we got some type are using this action
				if(removeActionCounter>0){
					retAList.add(action);	
				}
			}
			if(counter>0){
				//put this type into a list
				retTList.add(type);
			}
			
		}
		//there are still some types left 
		if(retTList.size()>0){
			mediaTypes = (DoubanMediaTypeConstant[])retTList.toArray(new DoubanMediaTypeConstant[retTList.size()]);
		}else{
			mediaTypes = new DoubanMediaTypeConstant[0];
			actions = new DoubanUserActionConstant[0];
		}
		

	}

	public Collection getRequests() {
		return this.requestCombination;
	}

	@Override
	public boolean areRequestsAcomplished() {
		// TODO Auto-generated method stub
		return (mediaTypes.length==0&& actions.length==0);
	}
}
